using DapperExtensions;
using SmartLink.Domain.Entity;
using SmartLink.IRepository;
using SmartLink.Repository.Base;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SmartLink.EnumLibrary;
using Dapper;
using SmartLink.Domain.ExpandEntity;

namespace SmartLink.Repository
{
    public class SYS_ModuleRepo : RepositoryBase<SYS_Module>, ISYS_ModuleRepo
    {
        public bool Exist(string code)
        {
            var predicate = Predicates.Field<SYS_Module>(f => f.Code, Operator.Eq, code.Trim());

            using (var conn = CreateConn())
            {
                IDatabase db = GetIDataBase(conn);
                var list = db.Count<SYS_Module>(predicate);
                return list > 0;
            }
        }

        public bool Repeat(int id, string newCode)
        {
            var predicate = new PredicateGroup
            {
                Operator = GroupOperator.And,
                Predicates = new List<IPredicate>
                    {
                        Predicates.Field<SYS_Module>(f => f.ID, Operator.Eq, id, true),
                        Predicates.Field<SYS_Module>(f => f.Name, Operator.Eq, newCode.Trim()),
                        Predicates.Field<SYS_Module>(f => f.IsDel, Operator.Eq, false)
                    }
            };

            using (var conn = CreateConn())
            {
                IDatabase db = GetIDataBase(conn);
                var list = db.Count<SYS_Module>(predicate);
                return list > 0;
            }
        }

        public IEnumerable<SYS_Module> GetImmediateChildren(int parentId)
        {
            var predicate = new PredicateGroup
            {
                Operator = GroupOperator.And,
                Predicates = new List<IPredicate>
                    {
                        Predicates.Field<SYS_Module>(f => f.ParentID, Operator.Eq, parentId),
                        Predicates.Field<SYS_Module>(f => f.IsDel, Operator.Eq, false)
                    }
            };

            IList<ISort> sort = new List<ISort> { Predicates.Sort<SYS_Module>(p => p.Sort) };
            using (var conn = CreateConn())
            {
                IDatabase db = GetIDataBase(conn);
                var list = db.GetList<SYS_Module>(predicate, sort);
                return list;
            }
        }

        public IEnumerable<SYS_Module> GetAuthorizedModules(AuthorizationOwnerTypeEnum ownerType, params int[] ownerIds)
        {
            var sql = $@"SELECT m.* FROM SYS_Module m
                                  JOIN PER_ActionAuthorization aa ON aa.ItemType={(int)AuthorizationItemTypeEnum.Module} AND aa.ItemID=m.ID
                                  WHERE aa.OwnerType={(int)ownerType} AND aa.OwnerID IN ({string.Join(",", ownerIds)})";
            using (var conn = CreateConn())
            {
                return conn.Query<SYS_Module>(sql);
            }
        }

        public bool ExistChildren(int id)
        {
            var predicate = Predicates.Field<SYS_Module>(f => f.ParentID, Operator.Eq, id);

            using (var conn = CreateConn())
            {
                IDatabase db = GetIDataBase(conn);
                var list = db.Count<SYS_Module>(predicate);
                return list > 0;
            }
        }

        public IEnumerable<SysModuleExpand> GetAllWithRelation(bool containsLogicDeleted)
        {
            var moduleEntities = GetAll(containsLogicDeleted);
            var selfRelateions = SelfTreeStructure(DapperHelper.GetTableName(typeof(SYS_Module)));
            var expand = moduleEntities.Join(selfRelateions, e => e.ID, r => r.ID, (e, r) => new SysModuleExpand
            {
                ID = e.ID,
                ParentID = e.ParentID,
                Code = e.Code,
                Name = e.Name,
                Description = e.Description,
                Enabled = e.Enabled,
                IconName = e.IconName,
                Sort = e.Sort,
                Url = e.Url,
                Depth = r.Depth,
                Path = r.Path,
                Creator = e.Creator,
                CreateTime = e.CreateTime,
                IsDel = e.IsDel,
            });
            return expand;
        }

        private IEnumerable<SelfRelationRow> SelfRelationTable()
        {
            var sql = @" SELECT id AS ID,parentId AS ParentID ,depth AS Depth, path AS Path FROM (
                             SELECT id,parentId,
                             @le:= IF (parentId = 0 ,0,  
                                 IF( LOCATE( CONCAT('|',parentId,':'),@pathlevel)   > 0  ,      
                                          SUBSTRING_INDEX( SUBSTRING_INDEX(@pathlevel,CONCAT('|',parentId,':'),-1),'|',1) +1
                                ,@le) ) depth
                             , @pathlevel:= CONCAT(@pathlevel,'|',id,':', @le ,'|') pathlevel
                              , @pathnodes:= IF( parentId =0,',0', 
                                   CONCAT_WS(',',
                                   IF( LOCATE( CONCAT('|',parentId,':'),@pathall) > 0  , 
                                       SUBSTRING_INDEX( SUBSTRING_INDEX(@pathall,CONCAT('|',parentId,':'),-1),'|',1)
                                      ,@pathnodes ) ,parentId  ) ) path
                            ,@pathall:=CONCAT(@pathall,'|',id,':', @pathnodes ,'|') pathall 
                                FROM  sys_module, 
                            (SELECT @le:=0,@pathlevel:='', @pathall:='',@pathnodes:='') vv
                            ORDER BY  parentId,id
                            ) src
                        ORDER BY id";
            using (var conn = DapperHelper.GetAllowUserVariableConnection())
            {
                var relationTable = conn.Query<SelfRelationRow>(sql);
                return relationTable;
            }
        }

        public IEnumerable<SYS_Module> GetOrgManagerModules()
        {
            var sql = "SELECT * FROM SYS_Module WHERE NOT FIND_IN_SET(Code, @ModuleConcatStr) AND IsDel=0";
            var superAdminOnlyModuleConcatStr = string.Join(",", SuperAdminOnlyModule.Modules);
            using (var conn = CreateConn())
            {
                return conn.Query<SYS_Module>(sql, new { ModuleConcatStr = superAdminOnlyModuleConcatStr });
            }
        }
    }
}

